#include <iostream>
using namespace std;

// 拥有 虚函数 的类对象，都有一个虚指针
// 虚指针指向虚函数表
// 虚函数表是一个 指针数组
// 数组内的指针指向 虚函数

// 通过上面的分析，可以从下至上的定义类型：
// Func 是一个函数类型 (虚函数)
typedef void Func(void);
// Func_ptr 是指向函数的指针类型 (虚函数指针)
typedef Func* Func_ptr;
// Func_ptr_arr 是一个数组类型，成员是 Func_ptr 类型(虚函数表)
typedef Func_ptr Func_ptr_arr[];
// Func_ptr_arr_ptr 是指向 Func_ptr 的指针(指向虚函数表的指针)
typedef Func_ptr_arr* Func_ptr_arr_ptr; 

class Base {
public:
  virtual void func1() {
    cout << "Base::func1()" << endl;
  }
  virtual void func2() {
    cout << "Base::func2()" << endl;
  }
  virtual void func3(int i, int j) {
    cout << "Base::func3(int): " 
         << "a: " << this->a
         << " i: " << i
         << " j: " << j << endl;
  }
  int a = 55;
};

void demo(Base* base_p) {
  // base_p 是对象 base 的地址
  // 也是 vptr 的地址
  // 将指各 base_p 的指针转换为指向 vptr 的指针
  Func_ptr_arr_ptr* vptr_ptr = (Func_ptr_arr_ptr*)(base_p);
  // 获取 vptr
  Func_ptr_arr_ptr vptr = *vptr_ptr;
  // vtbl 是一个数组。
  // 此处注释掉是因为数组需要用列表初始化 
  // Func_ptr_arr vtbl = *vptr;

  // 指向 func1 的指针
  Func_ptr func1_ptr = (*vptr)[0];
  // func1 是一个函数
  // 但是这样赋值是不合法的
  // 函数需要通过函数指针调用
  // 先注释掉
  // Func func1 = *func1_ptr;
  
  // 调用 func1()
  (*func1_ptr)();

  // 调用 func2()
  Func_ptr func2_ptr = *((*vptr) + 1);
  func2_ptr();

  // 调用 func3()
  // 定义一个 新的函数指针类型
  typedef void (*Func_int)(Base* p, int, int);
  Func_int func3_ptr = (Func_int)*((*vptr) + 2);
  func3_ptr(base_p, 100, 100);
}

int main() {
  Base base;
  demo(&base);

  return 0;
}
